import path from 'node:path';
import { Logger } from './logger';
import express, { type Express, Request, Response, NextFunction } from 'express';
export class NestApplication {
  // 在其内部私有化一个express 实例
  private readonly app: Express = express();
  // 创建中间件 use 方法
  use(middleware: any) {
    this.app.use(middleware);
  }
  // 创建构造函数
  constructor(protected readonly module) { }
  // 初始化配置工作
  async init() {
    // 取出模块所有控制器，然后做好路由配置
    const controllers = Reflect.getMetadata('controllers', this.module);
    // console.log("🚀 ~ NestApplication ~ init ~ controllers:", controllers)
    Logger.log(`Application is initializing`, 'InstanceLoader')
    // 路由映射核心是知道 什么样的请求方法什么样式的路径对应的那个处理函数
    for (const Controller of controllers) {
      // 创建每个控制器的实例
      const controller = new Controller();
      // 获取控制器上配置的路径前缀
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      Logger.log(`${Controller.name} {${prefix}}`, 'RoutesResolver')
      // const constructorPrototype = Object.getOwnPropertyNames(Reflect.getPrototypeOf(controller));
      const constructorPrototype = Controller.prototype;
      // 遍历类的原型上的方法名
      for (const methodName of Object.getOwnPropertyNames(constructorPrototype)) {
        // 获取原型上的方法 index
        const method = constructorPrototype[methodName]
        // 获取方法装饰器配置的请求方法
        const httpMethod = Reflect.getMetadata('method', method);
        // console.log("🚀 ~ NestApplication ~ init ~ httpMethod:", httpMethod)
        // 获取方法装饰器配置的请求路径
        const pathMetadata = Reflect.getMetadata('path', method);
        // console.log("🚀 ~ NestApplication ~ init ~ pathMetadata:", pathMetadata)
        // 如果方法名不存在
        if(!httpMethod) {
          continue;
        }
        // 拼接完整的路由路径
        const routerPath = path.posix.join('/', prefix, pathMetadata);
        // 配置路由，当客服端以 httpMethod 方法访问 routerPath 路径时，执行对应的处理函数
        this.app[httpMethod.toLowerCase()](routerPath, (req: Request, res: Response, next: NextFunction) => {
          // 获取装饰器上的参数
          const args = this.resolveParams(controller, methodName, req, res, next);
          // console.log("🚀 ~ NestApplication ~ this.app[httpMethod.toLowerCase ~ args:", args)
          // 执行Controller路径对应的方法
          const result = method.call(controller, ...args);
          // console.log(result, '--result0--')
          res.send(result);
        })
        Logger.log(`Mapped {${routerPath}, ${httpMethod}} route`, 'RoutesResolver')
      }
    }
    Logger.log(`Nest application successfully started`, 'InstanceLoader')
  }

  //
  private resolveParams(instance: any, methodName: string, req: Request, res: Response, next: NextFunction) {
    // 获取参数的元数据
    const existingParams = Reflect.getMetadata('params', instance, methodName) || [];
    //
    // return existingParams.sort((a, b) => a.parameterIndex - b.parameterIndex).map(paramMetadata => {
    // 为了兼容参数中没有控制器的情况
    return existingParams.map(paramMetadata => {
      const { key, data } = paramMetadata;
      switch(key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data ? req.query[data] : req.query;
        case 'Headers':
          return data ? req.headers[data] : req.headers;
        case 'Session':
          return data ? req.session[data] : req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data ? req.params[data] : req.params;
        default:
          return null;
      }
    })
  }

  async listen(port: number) {
    await this.init();
    // 调佣 express 实例的 listen 方法启动一个 HTTP 服务器，监听 port 端口
    this.app.listen(port, () => {
      Logger.log(`Application is running on http://localhost:${port}`, 'NestApplication');
    })
  }
}
